const FormData = require("form-data");
const fs = require("fs");
const path = require("path");
const http = require("http");
const https = require("https");
const url = require("url");
const buffer = require("buffer");
const randomstring = require("randomstring");
const axios = require("axios").default;
const uuid = require("uuid");

const getCookie = require("./getCookie");
const my_user_agent = require("./user-agent");


/**
 * @param {String} filename
 * @return {Promise<{ok:Boolean,data:{authToken:String,time:String,uptoken:String,userId:Number},msg:String}>}
 */
function getUploadToken(filename = "no-named.bin") {
  return new Promise(async (resolve) => {
    let codingsud_cookie = await getCookie.getCookie();
    axios.get("https://coding.net/api/upload_token", {
      params: {
        projectId: 3603729,
        fileName: filename,
        fileSize: 10 * 1024
      },
      headers: {
        cookie: codingsud_cookie
      }
    }).then(({ data, status }) => {
      let code = data['code'];
      if (code == 0) {
        let d = data['data'];
        let authToken = d['authToken'];
        let time = d['time'];
        let uptoken = d['uptoken'];
        let userId = d['userId'];
        resolve({
          ok: true,
          data: {
            authToken: authToken,
            time: time,
            uptoken: uptoken,
            userId: userId
          }
        })
      } else {
        resolve({
          ok: false,
          data: {},
          msg: "Code≠0 ;" + JSON.stringify(data['msg'])
        })
      }

    }).catch(error => {
      resolve({
        ok: false,
        data: {},
        msg: error
      })
    })

  })
}

const upload_url = "https://up.qbox.me/?dir=0";
const parsed_url = url.parse(upload_url);
/**
 * 
 * @param {String} full_path 
 */
function uploadSingle(full_path) {
  return new Promise(async (resolve, reject) => {
    let upload_token_data = await getUploadToken(path.basename(full_path));
    let form = new FormData;
    let file_stream = fs.createReadStream(full_path);
    form.append("file", file_stream, {
      filename: path.basename(full_path)
    });
    form.append("key", uuid());
    form.append("x:dir", "0");
    form.append("x:projectId", "3603729");
    form.append("token", upload_token_data.data.uptoken);
    form.append("x:time", upload_token_data.data.time);
    form.append("x:authToken", upload_token_data.data.authToken);
    form.append("x:userId", upload_token_data.data.userId);

    let headers = {
      "User-Agent": my_user_agent.getUserAgent(),
    };
    form.submit({
      host: parsed_url.host,
      path: parsed_url.path,
      protocol: parsed_url.protocol,
      headers: headers
    }, (err, res) => {
      if (err) {
        console.error(err);
        return reject(err);
      }
      let buf = new buffer.Buffer("");
      res.on("data", chunk => {
        buf += chunk;
      });
      res.on("end", () => {
        try {
          let obj = JSON.parse(buf);
          if (obj['error']) {
            reject(obj['error']);
          } else {
            let src = obj['data']['url'];
            console.log(path.basename(full_path));
            let fullurl = `` + src
            console.log(fullurl);
            resolve(fullurl);
          }
        } catch (e) {
          reject(e);
        }
      })
    })

  })
}

/**
 * @param {Number} x
 * @param {String} full_path 
 */
function uploadSingleForXTime(x, full_path) {
  let g = (function* () {
    for (let i = 1; i <= x; i++) {
      yield uploadSingle(full_path);
    }
  })();
  let it = g.next();
  return new Promise((resolve, reject) => {
    (function bootstrap() {
      if (it.done) {
        reject(x + "times failed");
      } else {
        it.value.then(() => {
          resolve();
        }).catch(e => {
          it = g.next();
          setTimeout($ => bootstrap(), 2000);
        })
      }
    })();
  })
}

if (!module.parent) {
  uploadSingle(path.join(__dirname, "./../tmp/294MB[SumiSora][Ichiban Ushiro no Daimaou][BDrip][11][BIG5][720P].mp4"))
}

module.exports = {
  uploadSingle: uploadSingle,
  uploadSingleForXTime: uploadSingleForXTime
}